#include "awi_dfu.h"

#define DFU_BUFFER_SIZE 8192

awi_dfu_t* awi_dfu_new()
{
	awi_dfu_t *dfu;

	dfu = (awi_dfu_t*)awi_malloc(sizeof(awi_dfu_t));
	if (NULL == dfu) {
		return NULL;
	}
	awi_dfu_unpack_init(&dfu->unpack);
	dfu->recv_func = NULL;
	dfu->recv_ths = NULL;
	dfu->send_func = NULL;
	dfu->send_ths = NULL;
	return dfu;
}

void awi_dfu_del(awi_dfu_t *dfu)
{
	if (NULL != dfu) {
		awi_dfu_unpack_clean(&dfu->unpack);
		awi_free(dfu);
	}
}

void awi_dfu_send(awi_dfu_t *dfu, uint16_t ctrl, uint16_t dst, uint16_t src, const uint8_t *payload, int bytes)
{
	uint8_t buffer[DFU_BUFFER_SIZE];

#if 0
	aw_print("send ctrl = %x dst = %x src = %x bytes = %d", ctrl, dst, src, bytes);
	printf("send payload = [");
	for (int i = 0; i < bytes; ++i){
		printf("%x ", payload[i]);
	}
	printf("]\r\n");
#endif
	
	int len = awi_dfu_pack_proc(buffer, DFU_BUFFER_SIZE, dst, src, ctrl, payload, bytes);
	if (len > 0) {
		if (dfu->send_func != NULL) {
			dfu->send_func(dfu->send_ths, (const uint8_t*)buffer, len);
		}
	}
	if (len < 0) {
		aw_print("pack dfu fail");
	}
}

void awi_dfu_set_send_notify(awi_dfu_t *dfu, void *notify_ths, awi_dfu_send_notify_func notify_func)
{
	dfu->send_func = notify_func;
	dfu->send_ths = notify_ths;
}

void awi_dfu_recv(awi_dfu_t *dfu, const uint8_t *data, int bytes)
{
	awi_dfu_unpack_t *unpack = &dfu->unpack; 

	int pos = 0;
	while (pos < bytes)
	{
		int consumed = 0;
		int ret = awi_dfu_unpack_feed(unpack, data + pos, bytes - pos, &consumed);
		if (ret != 0) {
			pos += consumed;
			awi_dfu_unpack_reset(unpack);
			continue;
		}
		pos += consumed;
		if (unpack->state == AWI_DFU_UNPACK_DONE) {
			if (dfu->recv_func != NULL) {
				dfu->recv_func(dfu->recv_ths, unpack->header.ctrl, unpack->header.dst, unpack->header.src, unpack->header.version,
								(const uint8_t*)(unpack->header.len > AWI_DFU_UNPACK_DEF_BUFFER_SIZE ? unpack->payload_extra : unpack->payload), unpack->header.len); 
			}
			awi_dfu_unpack_reset(unpack);
		}
	}
}

void awi_dfu_set_recv_notify(awi_dfu_t *dfu, void *notify_ths, awi_dfu_recv_notify_func notify_func)
{
	dfu->recv_func = notify_func;
	dfu->recv_ths = notify_ths;
}